"use strict"
import "../../lib/ramda.js";
import "../../lib/jquery.js";
import direct2d from "../../lib/direct2d.js";
import * as game from "./game.js";

const PC_PAGEWIDTH_RATE = 0.55
const TEMPLATE = {
    pbox: $("ux-template#pbox").html(),
    piece: $("ux-template#piece").html(),
    piece_nari: $("ux-template#piece-nari").html(),
    piece_inhand: $("ux-template#piece-inhand").html(),
    piece_sel_nari: $("ux-template#piece-sel-nari").html(),
    canmove: $("ux-template#canmove").html(),
    cursor: $("ux-template#cursor").html(),
}
const PIECE_NAMES = {
    [game.P_OU]: ["玉","王"],
    [game.P_HI]: ["飛","飞"],
    [game.P_RYU]: ["龍","竜"],
    [game.P_KAKU]: ["角"],
    [game.P_UMA]: ["馬","马"],
    [game.P_KIN]: ["金"],
    [game.P_NARIGIN]: ["全"],
    [game.P_NARIKEI]: ["圭"],
    [game.P_NARIKYO]: ["杏"],
    [game.P_TOKIN]: ["と"],
    [game.P_GIN]: ["銀","银"],
    [game.P_KEI]: ["桂"],
    [game.P_KYO]: ["香"],
    [game.P_FU]: ["步"],
}

const LOC_X = [
    "9","8","7","6","5","4","3","2","1",
]
const LOC_Y = [
    "一","二","三","四","五","六","七","八","九",
]
const TEBAN = [
    "", "☗", "☖"
]

const State = {
    fui: null,
}

function game_area(dom, io, fui) {
    const dom_pboxs = []
    for (const row of R.range(1, 12)) {
        const row_pboxs = []
        for (const col of R.range(1, 10)) {
            const html = TEMPLATE.pbox.replace("[ROW]",row).replace("[COL]",col)
            dom.append(html)
            const dom_pbox = dom.children().last()
            if (row < 2 || row > 10) {
                dom_pbox.addClass("pbox-inhand").attr("pc","0").attr("n","0")
            }
            row_pboxs.push(dom_pbox)
        }
        dom_pboxs.push(row_pboxs)
    }

    function piece_sel_nari_html(p) {
        const p_teban = game.Piece_teban(p)
        const p_class_all = [game.Piece_class(p), game.Piece_class(game.Piece_nari(p))]
        const words = p_class_all.map((p_class)=>{return PIECE_NAMES[p_class][(PIECE_NAMES[p_class].length > 1) ? ((p_teban == game.TEBAN_SENTE) ? 0 : 1) : 0]})
        const html = TEMPLATE.piece_sel_nari.replace("[CLASS]", (p_teban == game.TEBAN_GOTE) ? "in-pbox-piece in-pbox-gote" : "in-pbox-piece")
            .replace("[WORD-1]", words[0]).replace("[WORD-2]", words[1])
        return html
    }

    const cursor_canmoves = new Uint8Array(game.BOARD_SIZE * game.BOARD_SIZE)
    cursor_canmoves.fill(0)
    let dom_can_nari = null
    let canmoves = []
    let cursor_pbox = null
    function move_cursor(pbox_y, pbox_x) {
        if (io.get_status() != game.STATUS_NORMAL) {return}
        if (cursor_pbox != dom_pboxs[pbox_y][pbox_x]) {
            if (cursor_pbox != null) {
                cursor_pbox.children(".in-pbox-cursor").remove()
            }
            cursor_pbox = dom_pboxs[pbox_y][pbox_x]
            cursor_pbox.append(TEMPLATE.cursor)
        }
        const to_y = pbox_y-1
        const to_x = pbox_x
        const yx_canmove = cursor_canmoves[(to_y * game.BOARD_SIZE) + to_x]
        cursor_canmoves.fill(0)
        if (yx_canmove) {
            const ms = canmoves.filter((m)=>{return (m.loc_to == game.Loc(to_y, to_x))})
            if (ms.length > 1) {
                dom_pboxs[pbox_y][pbox_x].append(piece_sel_nari_html(io.get_piece(ms[0].loc_from)))
                dom_can_nari = dom_pboxs[pbox_y][pbox_x].children(".in-pbox-sel-nari")
                dom_can_nari.children("svg").on("click", function(e){
                    let dom = $(e.target)
                    while (dom.attr("mi") == undefined) {dom = dom.parent()}
                    io.on_move(ms[Number(dom.attr("mi"))])
                })
            } else {
                io.on_move(ms[0])
            }
        } else if (pbox_y < 1 || pbox_y > 9) {
            const pcur = (pbox_y < 1) ? game.TEBAN_GOTE : game.TEBAN_SENTE
            if (pcur == io.pcur()) {
                const p_class = Number(dom_pboxs[pbox_y][pbox_x].attr("pc"))
                const n = Number(dom_pboxs[pbox_y][pbox_x].attr("n"))
                if (n > 0) {
                    canmoves = io.get_canputs(game.Piece(p_class, pcur))
                    for (const m of canmoves) {
                        const [to_y,to_x] = [game.Loc_y(m.loc_to), game.Loc_x(m.loc_to)]
                        cursor_canmoves[(to_y * game.BOARD_SIZE) + to_x] = 1
                    }
                }
            }
        } else {
            const p = io.get_piece(game.Loc(to_y,to_x))
            const pcur = game.Piece_teban(p)
            if (pcur == io.pcur()) {
                canmoves = io.get_canmoves(game.Loc(to_y, to_x))
                for (const m of canmoves) {
                    const [to_y,to_x] = [game.Loc_y(m.loc_to), game.Loc_x(m.loc_to)]
                    cursor_canmoves[(to_y * game.BOARD_SIZE) + to_x] = 1
                }
            }
        }
    }

    function piece_html(p) {
        const p_class = game.Piece_class(p)
        const p_teban = game.Piece_teban(p)
        const word = PIECE_NAMES[p_class][(PIECE_NAMES[p_class].length > 1) ? ((p_teban == game.TEBAN_SENTE) ? 0 : 1) : 0]
        const template = game.Piece_is_nari(p) ? TEMPLATE.piece_nari : TEMPLATE.piece
        const html = template.replace("[CLASS]", (p_teban == game.TEBAN_GOTE) ? "in-pbox-piece in-pbox-gote" : "in-pbox-piece")
            .replace("[WORD]", word)
        return html
    }

    function piece_inhand_html(p, n) {
        const p_class = game.Piece_class(p)
        const p_teban = game.Piece_teban(p)
        const word = PIECE_NAMES[p_class][(PIECE_NAMES[p_class].length > 1) ? ((p_teban == game.TEBAN_SENTE) ? 0 : 1) : 0]
        const html = TEMPLATE.piece_inhand.replace("[CLASS]", (p_teban == game.TEBAN_GOTE) ? "in-pbox-piece in-pbox-gote" : "in-pbox-piece")
            .replace("[WORD]", word).replace("[N]", n)
        return html
    }

    function update_pbox(y,x,p) {
        const pbox = dom_pboxs[y+1][x]
        const pbox_attr = Number(pbox.attr("piece"))
        if (p != pbox_attr) {
            pbox.children(".in-pbox-piece").remove()
            if (p != game.P_EMPTY) {
                pbox.append(piece_html(p))
            }
            pbox.attr("piece", String(p))
        }
        if (io.round() > 0) {
            const r = io.record(io.round())
            const m = r.get_move()
            if (m.is_put() && (m.loc_to == game.Loc(y,x))) {
                if (! pbox.hasClass("pbox-put")) {pbox.addClass("pbox-put")}
            } else if ((m.loc_from == game.Loc(y,x)) || (m.loc_to == game.Loc(y,x))) {
                if (! pbox.hasClass("pbox-move")) {pbox.addClass("pbox-move")}
            } else {
                pbox.removeClass("pbox-move").removeClass("pbox-put")
            }
        } else {
            pbox.removeClass("pbox-move").removeClass("pbox-put")
        }
        if (cursor_canmoves[(y*game.BOARD_SIZE) + x]) {
            if (pbox.children(".in-pbox-canmove").length < 1) {
                if (p == game.P_EMPTY) {
                    pbox.append(TEMPLATE.canmove)
                } else {
                    pbox.addClass("pbox-eat")
                }
            }
        } else if (pbox.children(".in-pbox-canmove").length > 0) {
            pbox.children(".in-pbox-canmove").remove()
        } else if ((game.Piece_class(p) == game.P_OU) && (io.phase().can_attack(y,x) > 0)){
            pbox.addClass("pbox-eat")
        } else if (pbox.hasClass("pbox-eat")) {
            pbox.removeClass("pbox-eat")
        }
    }

    function update_inhands() {
        function with_teban(teban,y) {
            let x = 0
            for (const a of io.get_inhands(teban)) {
                const [pc, n] = a
                dom_pboxs[y][x].append(piece_inhand_html(game.Piece(pc, teban), n))
                dom_pboxs[y][x].attr("pc", String(pc)).attr("n", String(n))
                x += 1
            }
        }
        for (let i = 0; i < game.BOARD_SIZE; i++) {
            dom_pboxs[0][i].children(".in-pbox-piece").remove()
            dom_pboxs[10][i].children(".in-pbox-piece").remove()
        }
        with_teban(game.TEBAN_GOTE, 0)
        with_teban(game.TEBAN_SENTE, 10)
    }

    fui.frame_join(()=>{
        fui.event_poll("tap-piece").on((val,fn_take)=>{
            const [y,x] = val
            fn_take()
            move_cursor(y+1, x)
        })
        fui.event_poll("tap-inhand").on((val,fn_take)=>{
            const [y,x] = val
            fn_take()
            move_cursor((10 * y), x)
        })
        fui.event_poll("clear-sel-nari").on((_,fn_take)=>{
            fn_take()
            if (dom_can_nari != null) {
                const n = Number(dom_can_nari.attr("n"))
                if (n > 0){
                    dom_can_nari.remove()
                    dom_can_nari = null
                } else {
                    dom_can_nari.attr("n", String(n+1))
                }
            }
        })
        io.for_board(update_pbox)
        update_inhands()
    })
}

function game_status(dom, io, fui) {
    fui.frame_join(()=>{
        const round = io.round()
        const status = io.get_status()
        if (round > 0) {
            const r = io.record(round)
            const m = r.get_move()
            let same_last_loc = false
            if (round > 1) {
                const last_m = io.record(round-1).get_move()
                if (last_m.loc_to == m.loc_to) {same_last_loc = true}
            }
            const teban_show = TEBAN[r.get_teban()]
            const loc_show = same_last_loc ? "同" : `${LOC_X[game.Loc_x(m.loc_to)]}${LOC_Y[game.Loc_y(m.loc_to)]}`
            const p_name = PIECE_NAMES[r.get_class()]
            const p_show = (p_name.length > 1) ? p_name[(r.get_teban() == game.TEBAN_SENTE) ? 0 : 1] : p_name[0]
            let p_ext = ""
            if (m.is_nari()) {
                p_ext = "成"
            }
            let status_show = (status != game.STATUS_NORMAL) ? " 胜" : ""
            dom.html(`第${round}手 ${teban_show}${loc_show}${p_show}${p_ext}${status_show}`)
        } else {
            dom.html("等待先手(下方)")
        }
    })
}

function ai_status(dom, io, fui) {
    fui.frame_join(()=>{
        const str = io.ai_in_think() ? io.ai_status() : "IDLE"
        const ai_pcur = io.ai_in_think() ? io.pcur() : game.P_EMPTY
        const pcur_str = (ai_pcur == game.P_EMPTY) ? "" : `:${TEBAN[ai_pcur]}`
        direct2d.update_html(dom, `[AI${pcur_str}] ${str}`)
    })
}

function game_tools(io, fui) {
    const use_ai_sente = $("#use-ai-sente")
    const use_ai_gote = $("#use-ai-gote")
    use_ai_sente.on("click", function(){
        io.ai_player_set(game.TEBAN_SENTE, $(this).prop("checked"))
    })
    use_ai_gote.on("click", function(){
        io.ai_player_set(game.TEBAN_GOTE, $(this).prop("checked"))
    })
    fui.frame_join(()=>{
        if (use_ai_sente.prop("checked") != io.ai_player(game.TEBAN_SENTE)) {
            use_ai_sente.prop("checked", io.ai_player(game.TEBAN_SENTE))
        }
        if (use_ai_gote.prop("checked") != io.ai_player(game.TEBAN_GOTE)) {
            use_ai_gote.prop("checked", io.ai_player(game.TEBAN_GOTE))
        }
    })
}

function events(io, fui) {
    $(document.body).on("click", ()=>{
        fui.event_push("clear-sel-nari")
    })
    $(".pbox").on("click", function(e){
        let dom = $(e.target)
        while (! dom.hasClass("pbox")) {
            dom = dom.parent()
        }
        const x = Number(dom.css("grid-column").split(' ')[0]) - 1
        const y = Number(dom.css("grid-row").split(' ')[0])
        if (y < 2 || y > 10) {
            fui.event_push("tap-inhand", [(y < 2 ? 0 : 1),x])
        } else {
            fui.event_push("tap-piece", [y-2,x])
        }
    })
    $("#cmd-reset").on("click", function(){
        io.on_cmd_reset()
    })
    $("#cmd-undo").on("click", function(){
        io.on_cmd_undo()
    })
    $("#cmd-redo").on("click", function(){
        io.on_cmd_redo()
    })
    $("#cmd-undo-to-first").on("click", function(){
        io.on_cmd_undo_to_first()
    })
    $("#cmd-redo-to-last").on("click", function(){
        io.on_cmd_redo_to_last()
    })
}

function on_frame() {
    State.fui.on_frame()
}

function init(io) {
    if ("pc" == direct2d.adaption_mobile_width(PC_PAGEWIDTH_RATE)) {}
    const fui = new direct2d.FrameSystem()
    game_area($("#game-area"), io, fui)
    game_status($("#game-status"), io, fui)
    ai_status($("#ai-status"), io, fui)
    game_tools(io, fui)
    events(io, fui)
    State.fui = fui
}

export default {
    init,
    on_frame,
}
